//    entity language compiler Copyright (C) 2011 Vincent Belliard

//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation version 3 of the License.

//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.

//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

class T_string_iterator ;

extern unsigned strlen_utf8(const char *data) ;

#define FALSE 0
#define TRUE 1

class T_string_content
	{
	unsigned links_count ;
	unsigned allocated_size ;
public:
	unsigned size ;
	unsigned length ;
	char *data ;
	T_string_content(unsigned new_allocated_size, unsigned new_size, unsigned new_length, char *new_data)
		{
		/*fprintf(stderr, "new string_content %p <%s>\n", this, new_data) ;*/
		links_count = 1 ;
		allocated_size = new_allocated_size ;
		size = new_size ;
		length = new_length ;
		data = new_data ;
		}
	~T_string_content()
		{
		/*fprintf(stderr, "delete string_content %p <%s>\n", this, data) ;*/
		if (allocated_size > 0) delete data ;
		}
	void add_link(void) { /*fprintf(stderr, "string_content %p add_link => %d\n", this, links_count + 1) ;*/ links_count++ ; }
	void sub_link(void) { /*fprintf(stderr, "string_content %p sub_link => %d\n", this, links_count - 1) ;*/ links_count-- ; if (links_count == 0) delete this ; }
	} ;

class T_string
	{
public:
	T_string_content *content ;
	T_string(void) { content = new T_string_content(0, 0, 0, (char *)"") ; }
	T_string(const char *data) { /*fprintf(stderr, "new string %p from const\n", this) ;*/ content = new T_string_content(0, strlen(data), strlen_utf8(data), (char *)data) ; }
	T_string(char *data, unsigned data_size) { /*fprintf(stderr, "new string %p from buffer\n", this) ;*/ content = new T_string_content(data_size + 1, data_size, strlen_utf8(data), (char *)data) ; }
	T_string(const T_string &ref) { /*fprintf(stderr, "new string %p from %p\n", this, &ref) ;*/ content = ref.content ; content->add_link() ; }
	T_string(const T_string_iterator &start, const T_string_iterator &end) ;
	T_string(const T_string &left, const T_string &right) ;
	~T_string() { /*fprintf(stderr, "delete string %p\n", this) ;*/ content->sub_link() ; }
	const char *string(void) const { return content->data ; }
	void set(const char *data) { /*fprintf(stderr, "new string %p from const\n", this) ;*/ content->sub_link() ; content = new T_string_content(0, strlen(data), strlen_utf8(data), (char *)data) ; }
	void set(char *data, unsigned data_size) { /*fprintf(stderr, "new string %p from buffer\n", this) ;*/ content->sub_link() ; content = new T_string_content(data_size + 1, data_size, strlen_utf8(data), (char *)data) ; }
	void set(const T_string &ref) { /*fprintf(stderr, "new string %p from %p\n", this, &ref) ;*/ ref.content->add_link() ; content->sub_link() ; content = ref.content ; }
	void set(const T_string_iterator &start, const T_string_iterator &end) ;
	} ;

class T_string_iterator
	{
	T_string_content *content ;
public:
	unsigned offset ;
	unsigned utf8_offset ;
	T_string_iterator(void) { content = new T_string_content(0, 0, 0, (char *)"") ; offset = 0 ; }
	T_string_iterator(const T_string &ref) { content = ref.content ; content->add_link() ; offset = 0 ; utf8_offset = 0 ; }
	T_string_iterator(const T_string_iterator &ref) { content = ref.content ; content->add_link() ; offset = ref.offset ; utf8_offset = ref.utf8_offset ; }
	T_string_content *get_content(void) const { return content ; }
	char *get_from(void) const { return content->data + utf8_offset ; }
	unsigned current(void) const ;
	bool operator==(const T_string_iterator &ref) const { return (offset == ref.offset) && (content == ref.content) ; }
	void set(T_string &ref) { ref.content->add_link() ; content->sub_link() ; content = ref.content ; offset = 0 ; utf8_offset = 0 ; }
	void set(const T_string_iterator &ref) { ref.content->add_link() ; content->sub_link() ; content = ref.content ; offset = ref.offset ; utf8_offset = ref.utf8_offset ; }
	void increment(void) ;
	void restart(void) { offset = 0 ; utf8_offset = 0 ; }
	} ;

template<class T> class LINK
	{
public:
	T *previous ;
	T *next ;
	LINK(void) { previous = NULL ; next = NULL ; }
	} ;

template<class T> class LIST
	{
public:
	T *first ;
	T *last ;
	unsigned count ;
	LIST(void) { first = NULL ; last = NULL ; count = 0 ; } ;
	void insert(T *new_item)
		{
		new_item->previous = last ;
		new_item->next = NULL ;
		if (last == NULL) first = new_item ; else last->next = new_item ;
		last = new_item ;
		count++ ;
		}
	void remove(T *old_item)
		{
		if (old_item->previous == NULL) first = old_item->next ;
		else old_item->previous->next = old_item->next ;
		if (old_item->next == NULL) last = old_item->previous ;
		else old_item->next->previous = old_item->previous ;
		count-- ;
		}
	} ;
